<template>
  <div class="_fc_struct">
    <a-button @click="visible = true" style="width: 100%">{{
      title || t("struct.title")
    }}</a-button>
    <a-modal
      :title="title || t('struct.title')"
      draggable
      v-model:visible="visible"
    >
      <div ref="editor" v-if="visible"></div>
      <template #footer>
        <span class="dialog-footer">
          <span class="_fc_err" v-if="err"
            >{{ t("struct.error") }}{{ err !== true ? err : "" }}</span
          >
          <a-button @click="visible = false" size="small">{{
            t("struct.cancel")
          }}</a-button>
          <a-button type="primary" @click="onOk" size="small">{{
            t("struct.submit")
          }}</a-button>
        </span>
      </template>
    </a-modal>
  </div>
</template>

<script>
import "codemirror/lib/codemirror.css";
import CodeMirror from "codemirror/lib/codemirror";
import "codemirror/mode/javascript/javascript";
import { deepParseFn, toJSON } from "../utils/index";
import { deepCopy } from "@form-create/utils/lib/deepextend";
import { defineComponent } from "vue";

export default defineComponent({
  name: "Struct",
  props: {
    modelValue: [Object, Array, Function],
    title: String,
    defaultValue: {
      require: false,
    },
    validate: Function,
  },
  inject: ["designer"],
  data() {
    return {
      editor: null,
      visible: false,
      err: false,
      oldVal: null,
      t: this.designer.setupState.t,
    };
  },
  watch: {
    modelValue() {
      this.load();
    },
    visible(n) {
      if (n) {
        this.load();
      } else {
        this.err = false;
      }
    },
  },
  methods: {
    load() {
      const val = toJSON(
        deepParseFn(
          this.modelValue ? deepCopy(this.modelValue) : this.defaultValue
        )
      );
      this.oldVal = val;
      this.$nextTick(() => {
        this.editor = CodeMirror(this.$refs.editor, {
          lineNumbers: true,
          mode: "javascript",
          autoRefresh: true,
          gutters: ["CodeMirror-lint-markers"],
          lint: true,
          line: true,
          tabSize: 2,
          lineWrapping: true,
          value: val || "",
        });
      });
    },
    onOk() {
      const str = this.editor.getValue();
      let val;
      try {
        val = new Function("return " + str)();
      } catch (e) {
        this.err = ` (${e})`;
        return;
      }
      if (this.validate && false === this.validate(val)) {
        this.err = true;
        return;
      }
      this.visible = false;
      if (toJSON(val, null, 2) !== this.oldVal) {
        this.$emit("update:modelValue", val);
      }
    },
  },
});
</script>

<style>
._fc_struct {
  width: 100%;
}

._fc_struct .CodeMirror {
  height: 450px;
}

._fc_struct .CodeMirror-line {
  line-height: 16px !important;
  font-size: 13px !important;
}

.CodeMirror-lint-tooltip {
  z-index: 888 !important;
}

._fc_struct .arco-modal-body {
  padding: 0 20px;
}

._fc_err {
  color: red;
  float: left;
  text-align: left;
  width: 65%;
}

._fc_struct .CodeMirror-sizer {
  font-size: 13px;
  position: relative;
  border-right: 30px solid transparent;
}
</style>
